package com.example.caoh.shiro;

import java.util.List;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.example.caoh.entity.SysResources;
import com.example.caoh.entity.SysUser;
import com.example.caoh.service.sys.SysResourcesService;
import com.example.caoh.service.sys.SysUserService;
import com.example.caoh.utils.CipherUtil;
import com.example.caoh.utils.Const;

public class MyShiroRealm extends AuthorizingRealm {
	private static org.slf4j.Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);

	// 如果项目中用到了事物，@Autowired注解会使事物失效，可以自己用get方法获取值
	@Autowired
	private SysUserService userService;
	@Autowired
	private SysResourcesService resourcesService;

	/**
	 * 认证信息.(身份验证) : Authentication 是用来验证用户身份
	 *
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
			throws AuthenticationException {
		logger.info("---------------- 执行 Shiro 凭证认证 ----------------------");
		// 获取用户的输入的账号.
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		AuthenticationInfo authenticationInfo = null;
		String username = new String(token.getUsername());// 用户名
		String password = new String(token.getPassword());// 密码
		SysUser user = userService.selectByLongName(username);
		if (user == null)
			throw new UnknownAccountException();
		if (0 == user.getStatus()) {
			throw new DisabledAccountException(); // 帐号锁定
		}
		String pwdEncrypt = CipherUtil.createPwdEncrypt(username, password, user.getSalt());
		if (user.getPassword().equals(pwdEncrypt)) {
			authenticationInfo = new SimpleAuthenticationInfo(user, // 用户
					password, // 密码
					getName() // realm name
			);
			// 当验证都通过后，把用户信息放在session里
			this.setSession(Const.SESSION_USER, user);

		} else {
			throw new IncorrectCredentialsException(); /* 错误认证异常 */
		}
		return authenticationInfo;

	}

	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		logger.info("---------------- 执行 Shiro 权限获取 ---------------------");
		Object principal = principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		if (principal instanceof SysUser) {
			SysUser userLogin = (SysUser) principal;

			// String role_id = userLogin.getRoleId();
			// String role_name = roleService.getOneById(role_id).getRoleName();
			// Set<String> roles = new TreeSet();
			// roles.add(role_name);
			// authorizationInfo.addRoles(roles);
			// Set<String> permissions =
			// userService.findPermissionsByUserId(userLogin.getId());
			// authorizationInfo.addStringPermissions(permissions);

			List<SysResources> resourcesList = resourcesService.loadUserResources(userLogin.getId());
			// 权限信息对象info,用来存放查出的用户的所有的角色（role）及权限（permission）
			for (SysResources resources : resourcesList) {
				authorizationInfo.addStringPermission(resources.getResourceUrl());
			}
		}
		logger.info("---- 获取到以下权限 ----");
		logger.info(authorizationInfo.getStringPermissions().toString());
		logger.info("---------------- Shiro 权限获取成功 ----------------------");
		return authorizationInfo;
	}

	
	private void setSession(Object key, Object value) {
        Subject currentUser = SecurityUtils.getSubject();
        if (null != currentUser) {
            Session session = currentUser.getSession();
            if (null != session) {
                session.setAttribute(key, value);
            }
        }
    }
}
